home *** CD-ROM | disk | FTP | other *** search
/ Workbench Add-On / Workbench Add-On - Volume 1.iso / BBS-Archive / Comm / AmiTCP30b2.lha / src / rpclib / clnt_udp.c < prev    next >
C/C++ Source or Header  |  1994-03-09  |  13KB  |  489 lines

  1. /*
  2.  * $Id: clnt_udp.c,v 1.2 1993/11/10 01:51:36 jraja Exp $
  3.  *
  4.  * $Log: clnt_udp.c,v $
  5.  * Revision 1.2  1993/11/10  01:51:36  jraja
  6.  * Fixed includes, added ANSI prototypes.
  7.  * Added AMIGA specific includes.
  8.  * Fixed various types.
  9.  * Changed close() to CloseSocket() for the AMITCP.
  10.  * Changed ioctl() to IoctlSocket() for the AMITCP.
  11.  * Removed EINTR handling for the AMITCP (lets CTRL-C come through).
  12.  *
  13.  */
  14. /* @(#)clnt_udp.c    2.2 88/08/01 4.0 RPCSRC */
  15. /*
  16.  * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
  17.  * unrestricted use provided that this legend is included on all tape
  18.  * media and as a part of the software program in whole or part.  Users
  19.  * may copy or modify Sun RPC without charge, but are not authorized
  20.  * to license or distribute it to anyone else except as part of a product or
  21.  * program developed by the user.
  22.  * 
  23.  * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
  24.  * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
  25.  * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
  26.  * 
  27.  * Sun RPC is provided with no support and without any obligation on the
  28.  * part of Sun Microsystems, Inc. to assist in its use, correction,
  29.  * modification or enhancement.
  30.  * 
  31.  * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
  32.  * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
  33.  * OR ANY PART THEREOF.
  34.  * 
  35.  * In no event will Sun Microsystems, Inc. be liable for any lost revenue
  36.  * or profits or other special, indirect and consequential damages, even if
  37.  * Sun has been advised of the possibility of such damages.
  38.  * 
  39.  * Sun Microsystems, Inc.
  40.  * 2550 Garcia Avenue
  41.  * Mountain View, California  94043
  42.  */
  43. #if !defined(lint) && defined(SCCSIDS)
  44. static char sccsid[] = "@(#)clnt_udp.c 1.39 87/08/11 Copyr 1984 Sun Micro";
  45. #endif
  46.  
  47. /*
  48.  * clnt_udp.c, Implements a UDP/IP based, client side RPC.
  49.  *
  50.  * Copyright (C) 1984, Sun Microsystems, Inc.
  51.  */
  52.  
  53. #include <sys/param.h>
  54. #include <rpc/rpc.h>
  55. #include <sys/socket.h>
  56. #include <sys/ioctl.h>
  57. #include <netdb.h>
  58. #include <errno.h>
  59. #include <rpc/pmap_clnt.h>
  60. #include <stdio.h>
  61.  
  62. #ifdef AMIGA
  63. #include <proto/exec.h>
  64. #endif
  65.  
  66. /*
  67.  * UDP bases client side rpc operations
  68.  */
  69. static enum clnt_stat    clntudp_call(CLIENT * h, u_long proc,
  70.                      xdrproc_t xdr_args, caddr_t args_ptr,
  71.                      xdrproc_t xdr_results,
  72.                      caddr_t results_ptr,
  73.                      struct timeval timeout);
  74. static void        clntudp_abort(CLIENT * h);
  75. static void        clntudp_geterr(CLIENT * h, struct rpc_err * errp);
  76. static bool_t        clntudp_freeres(CLIENT * cl, 
  77.                     xdrproc_t xdr_res, caddr_t res_ptr);
  78. static bool_t           clntudp_control(CLIENT * cl,
  79.                     u_int request, caddr_t info);
  80. static void        clntudp_destroy(CLIENT * h);
  81.  
  82. static struct clnt_ops udp_ops = {
  83.     clntudp_call,
  84.     clntudp_abort,
  85.     clntudp_geterr,
  86.     clntudp_freeres,
  87.     clntudp_destroy,
  88.     clntudp_control
  89. };
  90.  
  91. /* 
  92.  * Private data kept per client handle
  93.  */
  94. struct cu_data {
  95.     int           cu_sock;
  96.     bool_t           cu_closeit;
  97.     struct sockaddr_in cu_raddr;
  98.     int           cu_rlen;
  99.     struct timeval       cu_wait;
  100.     struct timeval     cu_total;
  101.     struct rpc_err       cu_error;
  102.     XDR           cu_outxdrs;
  103.     u_int           cu_xdrpos;
  104.     u_int           cu_sendsz;
  105.     char           *cu_outbuf;
  106.     u_int           cu_recvsz;
  107.     char           cu_inbuf[1];
  108. };
  109.  
  110. /*
  111.  * Create a UDP based client handle.
  112.  * If *sockp<0, *sockp is set to a newly created UPD socket.
  113.  * If raddr->sin_port is 0 a binder on the remote machine
  114.  * is consulted for the correct port number.
  115.  * NB: It is the clients responsibility to close *sockp.
  116.  * NB: The rpch->cl_auth is initialized to null authentication.
  117.  *     Caller may wish to set this something more useful.
  118.  *
  119.  * wait is the amount of time used between retransmitting a call if
  120.  * no response has been heard;  retransmition occurs until the actual
  121.  * rpc call times out.
  122.  *
  123.  * sendsz and recvsz are the maximum allowable packet sizes that can be
  124.  * sent and received.
  125.  */
  126. CLIENT *
  127. clntudp_bufcreate(raddr, program, version, wait, sockp, sendsz, recvsz)
  128.     struct sockaddr_in *raddr;
  129.     u_long program;
  130.     u_long version;
  131.     struct timeval wait;
  132.     register int *sockp;
  133.     u_int sendsz;
  134.     u_int recvsz;
  135. {
  136.     CLIENT *cl;
  137.     register struct cu_data *cu;
  138.     struct timeval now;
  139.     struct rpc_msg call_msg;
  140.  
  141.     cl = (CLIENT *)mem_alloc(sizeof(CLIENT));
  142.     if (cl == NULL) {
  143.         (void) fprintf(stderr, "clntudp_create: out of memory\n");
  144.         rpc_createerr.cf_stat = RPC_SYSTEMERROR;
  145.         rpc_createerr.cf_error.re_errno = errno;
  146.         goto fooy;
  147.     }
  148.     sendsz = ((sendsz + 3) / 4) * 4;
  149.     recvsz = ((recvsz + 3) / 4) * 4;
  150.     cu = (struct cu_data *)mem_alloc(sizeof(*cu) + sendsz + recvsz);
  151.     if (cu == NULL) {
  152.         (void) fprintf(stderr, "clntudp_create: out of memory\n");
  153.         rpc_createerr.cf_stat = RPC_SYSTEMERROR;
  154.         rpc_createerr.cf_error.re_errno = errno;
  155.         goto fooy;
  156.     }
  157.     cu->cu_outbuf = &cu->cu_inbuf[recvsz];
  158.  
  159.     (void)gettimeofday(&now, (struct timezone *)0);
  160.     if (raddr->sin_port == 0) {
  161.         u_short port;
  162.         if ((port =
  163.             pmap_getport(raddr, program, version, IPPROTO_UDP)) == 0) {
  164.             goto fooy;
  165.         }
  166.         raddr->sin_port = htons(port);
  167.     }
  168.     cl->cl_ops = &udp_ops;
  169.     cl->cl_private = (caddr_t)cu;
  170.     cu->cu_raddr = *raddr;
  171.     cu->cu_rlen = sizeof (cu->cu_raddr);
  172.     cu->cu_wait = wait;
  173.     cu->cu_total.tv_sec = -1;
  174.     cu->cu_total.tv_usec = -1;
  175.     cu->cu_sendsz = sendsz;
  176.     cu->cu_recvsz = recvsz;
  177. #ifdef AMIGA
  178.     call_msg.rm_xid = (u_long)FindTask(NULL) ^ now.tv_sec ^ now.tv_usec;
  179. #else
  180.     call_msg.rm_xid = getpid() ^ now.tv_sec ^ now.tv_usec;
  181. #endif
  182.     call_msg.rm_direction = CALL;
  183.     call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION;
  184.     call_msg.rm_call.cb_prog = program;
  185.     call_msg.rm_call.cb_vers = version;
  186.     xdrmem_create(&(cu->cu_outxdrs), cu->cu_outbuf,
  187.         sendsz, XDR_ENCODE);
  188.     if (! xdr_callhdr(&(cu->cu_outxdrs), &call_msg)) {
  189.         goto fooy;
  190.     }
  191.     cu->cu_xdrpos = XDR_GETPOS(&(cu->cu_outxdrs));
  192.     if (*sockp < 0) {
  193.         int dontblock = 1;
  194.  
  195.         *sockp = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
  196.         if (*sockp < 0) {
  197.             rpc_createerr.cf_stat = RPC_SYSTEMERROR;
  198.             rpc_createerr.cf_error.re_errno = errno;
  199.             goto fooy;
  200.         }
  201.         /* attempt to bind to prov port */
  202.         (void)bindresvport(*sockp, (struct sockaddr_in *)0);
  203.         /* the sockets rpc controls are non-blocking */
  204. #ifdef AMITCP
  205.         (void)IoctlSocket(*sockp, FIONBIO, (char *) &dontblock);
  206. #else
  207.         (void)ioctl(*sockp, FIONBIO, (char *) &dontblock);
  208. #endif
  209.         cu->cu_closeit = TRUE;
  210.     } else {
  211.         cu->cu_closeit = FALSE;
  212.     }
  213.     cu->cu_sock = *sockp;
  214.     cl->cl_auth = authnone_create();
  215.     return (cl);
  216. fooy:
  217.     if (cu)
  218.         mem_free((caddr_t)cu, sizeof(*cu) + sendsz + recvsz);
  219.     if (cl)
  220.         mem_free((caddr_t)cl, sizeof(CLIENT));
  221.     return ((CLIENT *)NULL);
  222. }
  223.  
  224. CLIENT *
  225. clntudp_create(raddr, program, version, wait, sockp)
  226.     struct sockaddr_in *raddr;
  227.     u_long program;
  228.     u_long version;
  229.     struct timeval wait;
  230.     register int *sockp;
  231. {
  232.  
  233.     return(clntudp_bufcreate(raddr, program, version, wait, sockp,
  234.         UDPMSGSIZE, UDPMSGSIZE));
  235. }
  236.  
  237. static enum clnt_stat 
  238. clntudp_call(cl, proc, xargs, argsp, xresults, resultsp, utimeout)
  239.     register CLIENT    *cl;        /* client handle */
  240.     u_long        proc;        /* procedure number */
  241.     xdrproc_t    xargs;        /* xdr routine for args */
  242.     caddr_t        argsp;        /* pointer to args */
  243.     xdrproc_t    xresults;    /* xdr routine for results */
  244.     caddr_t        resultsp;    /* pointer to results */
  245.     struct timeval    utimeout;    /* seconds to wait before giving up */
  246. {
  247.     register struct cu_data *cu = (struct cu_data *)cl->cl_private;
  248.     register XDR *xdrs;
  249.     register int outlen;
  250.     register int inlen;
  251. #ifdef AMITCP
  252.     long fromlen;
  253. #else
  254.     int fromlen;
  255. #endif
  256. #ifdef FD_SETSIZE
  257.     fd_set readfds;
  258.     fd_set mask;
  259. #else
  260.     int readfds;
  261.     register int mask;
  262. #endif /* def FD_SETSIZE */
  263.     struct sockaddr_in from;
  264.     struct rpc_msg reply_msg;
  265.     XDR reply_xdrs;
  266.     struct timeval time_waited;
  267.     bool_t ok;
  268.     int nrefreshes = 2;    /* number of times to refresh cred */
  269. #ifdef AMITCP
  270.     struct timeval timeout, t_temp;
  271. #else
  272.     struct timeval timeout;
  273. #endif
  274.     if (cu->cu_total.tv_usec == -1) {
  275.         timeout = utimeout;     /* use supplied timeout */
  276.     } else {
  277.         timeout = cu->cu_total; /* use default timeout */
  278.     }
  279.  
  280.     time_waited.tv_sec = 0;
  281.     time_waited.tv_usec = 0;
  282. call_again:
  283.     xdrs = &(cu->cu_outxdrs);
  284.     xdrs->x_op = XDR_ENCODE;
  285.     XDR_SETPOS(xdrs, cu->cu_xdrpos);
  286.     /*
  287.      * the transaction is the first thing in the out buffer
  288.      */
  289.     (*(u_short *)(cu->cu_outbuf))++;
  290.     if ((! XDR_PUTLONG(xdrs, (long *)&proc)) ||
  291.         (! AUTH_MARSHALL(cl->cl_auth, xdrs)) ||
  292.         (! (*xargs)(xdrs, argsp)))
  293.         return (cu->cu_error.re_status = RPC_CANTENCODEARGS);
  294.     outlen = (int)XDR_GETPOS(xdrs);
  295.  
  296. send_again:
  297.     if (sendto(cu->cu_sock, cu->cu_outbuf, outlen, 0,
  298.         (struct sockaddr *)&(cu->cu_raddr), cu->cu_rlen)
  299.         != outlen) {
  300.         cu->cu_error.re_errno = errno;
  301.         return (cu->cu_error.re_status = RPC_CANTSEND);
  302.     }
  303.  
  304.     /*
  305.      * Hack to provide rpc-based message passing
  306.      */
  307.     if (timeout.tv_sec == 0 && timeout.tv_usec == 0) {
  308.         return (cu->cu_error.re_status = RPC_TIMEDOUT);
  309.     }
  310.     /*
  311.      * sub-optimal code appears here because we have
  312.      * some clock time to spare while the packets are in flight.
  313.      * (We assume that this is actually only executed once.)
  314.      */
  315.     reply_msg.acpted_rply.ar_verf = _null_auth;
  316.     reply_msg.acpted_rply.ar_results.where = resultsp;
  317.     reply_msg.acpted_rply.ar_results.proc = xresults;
  318. #ifdef FD_SETSIZE
  319.     FD_ZERO(&mask);
  320.     FD_SET(cu->cu_sock, &mask);
  321. #else
  322.     mask = 1 << cu->cu_sock;
  323. #endif /* def FD_SETSIZE */
  324.     for (;;) {
  325.         readfds = mask;
  326.         switch (select(_rpc_dtablesize(), &readfds, NULL, 
  327.                    NULL, &(t_temp = cu->cu_wait))) {
  328.  
  329.         case 0:
  330.             time_waited.tv_sec += cu->cu_wait.tv_sec;
  331.             time_waited.tv_usec += cu->cu_wait.tv_usec;
  332.             while (time_waited.tv_usec >= 1000000) {
  333.                 time_waited.tv_sec++;
  334.                 time_waited.tv_usec -= 1000000;
  335.             }
  336.             if ((time_waited.tv_sec < timeout.tv_sec) ||
  337.                 ((time_waited.tv_sec == timeout.tv_sec) &&
  338.                 (time_waited.tv_usec < timeout.tv_usec)))
  339.                 goto send_again;    
  340.             return (cu->cu_error.re_status = RPC_TIMEDOUT);
  341.  
  342.         /*
  343.          * buggy in other cases because time_waited is not being
  344.          * updated.
  345.          */
  346.         case -1:
  347. #ifndef AMITCP /* EINTR is returned in case of a CTRL-C by default */
  348.             if (errno == EINTR)
  349.                 continue;    
  350. #endif
  351.             cu->cu_error.re_errno = errno;
  352.             return (cu->cu_error.re_status = RPC_CANTRECV);
  353.         }
  354. #ifndef AMITCP /* EINTR is returned in case of a CTRL-C by default */
  355.         do {
  356. #endif
  357.             fromlen = sizeof(struct sockaddr);
  358.             inlen = recvfrom(cu->cu_sock, cu->cu_inbuf, 
  359.                 (int) cu->cu_recvsz, 0,
  360.                 (struct sockaddr *)&from, &fromlen);
  361. #ifndef AMITCP /* EINTR is returned in case of a CTRL-C by default */
  362.         } while (inlen < 0 && errno == EINTR);
  363. #endif
  364.         if (inlen < 0) {
  365.             if (errno == EWOULDBLOCK)
  366.                 continue;    
  367.             cu->cu_error.re_errno = errno;
  368.             return (cu->cu_error.re_status = RPC_CANTRECV);
  369.         }
  370.         if (inlen < sizeof(u_long))
  371.             continue;    
  372.         /* see if reply transaction id matches sent id */
  373.         if (*((u_long *)(cu->cu_inbuf)) != *((u_long *)(cu->cu_outbuf)))
  374.             continue;    
  375.         /* we now assume we have the proper reply */
  376.         break;
  377.     }
  378.  
  379.     /*
  380.      * now decode and validate the response
  381.      */
  382.     xdrmem_create(&reply_xdrs, cu->cu_inbuf, (u_int)inlen, XDR_DECODE);
  383.     ok = xdr_replymsg(&reply_xdrs, &reply_msg);
  384.     /* XDR_DESTROY(&reply_xdrs);  save a few cycles on noop destroy */
  385.     if (ok) {
  386.         _seterr_reply(&reply_msg, &(cu->cu_error));
  387.         if (cu->cu_error.re_status == RPC_SUCCESS) {
  388.             if (! AUTH_VALIDATE(cl->cl_auth,
  389.                 &reply_msg.acpted_rply.ar_verf)) {
  390.                 cu->cu_error.re_status = RPC_AUTHERROR;
  391.                 cu->cu_error.re_why = AUTH_INVALIDRESP;
  392.             }
  393.             if (reply_msg.acpted_rply.ar_verf.oa_base != NULL) {
  394.                 xdrs->x_op = XDR_FREE;
  395.                 (void)xdr_opaque_auth(xdrs,
  396.                     &(reply_msg.acpted_rply.ar_verf));
  397.             } 
  398.         }  /* end successful completion */
  399.         else {
  400.             /* maybe our credentials need to be refreshed ... */
  401.             if (nrefreshes > 0 && AUTH_REFRESH(cl->cl_auth)) {
  402.                 nrefreshes--;
  403.                 goto call_again;
  404.             }
  405.         }  /* end of unsuccessful completion */
  406.     }  /* end of valid reply message */
  407.     else {
  408.         cu->cu_error.re_status = RPC_CANTDECODERES;
  409.     }
  410.     return (cu->cu_error.re_status);
  411. }
  412.  
  413. static void
  414. clntudp_geterr(cl, errp)
  415.     CLIENT *cl;
  416.     struct rpc_err *errp;
  417. {
  418.     register struct cu_data *cu = (struct cu_data *)cl->cl_private;
  419.  
  420.     *errp = cu->cu_error;
  421. }
  422.  
  423.  
  424. static bool_t
  425. clntudp_freeres(cl, xdr_res, res_ptr)
  426.     CLIENT *cl;
  427.     xdrproc_t xdr_res;
  428.     caddr_t res_ptr;
  429. {
  430.     register struct cu_data *cu = (struct cu_data *)cl->cl_private;
  431.     register XDR *xdrs = &(cu->cu_outxdrs);
  432.  
  433.     xdrs->x_op = XDR_FREE;
  434.     return ((*xdr_res)(xdrs, res_ptr));
  435. }
  436.  
  437. static void 
  438. clntudp_abort(CLIENT *h)
  439. {
  440. }
  441.  
  442. static bool_t
  443. clntudp_control(cl, request, info)
  444.     CLIENT *cl;
  445.     u_int request;
  446.     char *info;
  447. {
  448.     register struct cu_data *cu = (struct cu_data *)cl->cl_private;
  449.  
  450.     switch (request) {
  451.     case CLSET_TIMEOUT:
  452.         cu->cu_total = *(struct timeval *)info;
  453.         break;
  454.     case CLGET_TIMEOUT:
  455.         *(struct timeval *)info = cu->cu_total;
  456.         break;
  457.     case CLSET_RETRY_TIMEOUT:
  458.         cu->cu_wait = *(struct timeval *)info;
  459.         break;
  460.     case CLGET_RETRY_TIMEOUT:
  461.         *(struct timeval *)info = cu->cu_wait;
  462.         break;
  463.     case CLGET_SERVER_ADDR:
  464.         *(struct sockaddr_in *)info = cu->cu_raddr;
  465.         break;
  466.     default:
  467.         return (FALSE);
  468.     }
  469.     return (TRUE);
  470. }
  471.     
  472. static void
  473. clntudp_destroy(cl)
  474.     CLIENT *cl;
  475. {
  476.     register struct cu_data *cu = (struct cu_data *)cl->cl_private;
  477.  
  478.     if (cu->cu_closeit) {
  479. #ifdef AMITCP
  480.         (void)CloseSocket(cu->cu_sock);
  481. #else
  482.         (void)close(cu->cu_sock);
  483. #endif
  484.     }
  485.     XDR_DESTROY(&(cu->cu_outxdrs));
  486.     mem_free((caddr_t)cu, (sizeof(*cu) + cu->cu_sendsz + cu->cu_recvsz));
  487.     mem_free((caddr_t)cl, sizeof(CLIENT));
  488. }
  489.